/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2008-2011, Salzburg Research. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * - Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * - Neither the name of the KiWi Project nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * Contributor(s):
 * sschaffe
 *
 * File Info:
 * User: sschaffe
 * Date: 2011/01/18
 * Time: 10:29
 *
 * Project: KiWi2, kiwi-core module
 */

package kiwi.core.model.versioning;

import kiwi.core.model.rdf.KiWiNamespace;
import kiwi.core.model.rdf.KiWiNode;
import kiwi.core.model.rdf.KiWiTriple;
import kiwi.core.model.user.KiWiUser;
import org.hibernate.annotations.*;
import org.hibernate.annotations.Cache;

import javax.persistence.*;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import java.util.Collection;
import java.util.Date;
import java.util.Set;

/**
 * A version represents a single update to the KiWi system and consists of a list of references to:
 * <ul>
 * <li>added and removed nodes</li>
 * <li>added and removed triples</li>
 * <li>added and removed namespaces</li>
 * </ul>
 * The version is considered immutable, because it is only stored and never updated in the database.
 *
 * <p/>
 * User: sschaffe
 */
@javax.persistence.Entity
@org.hibernate.annotations.Entity(mutable=false,optimisticLock= OptimisticLockType.VERSION)
@Immutable
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
@BatchSize(size = 100)
@NamedQueries({
        @NamedQuery(
                name  = "versioning.listVersions",
                query = "select v from Version v order by v.created desc"
        ),
        @NamedQuery(
                name  = "versioning.listVersionsByNode",
                query = "select v from Version v " +
                        "where :node = v.addedNodes or :node = v.removedNodes " +
                        "order by v.created desc"
        )
})
public class Version {

    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    private Long id;


    /**
     * The nodes that have been added in this version.
     */
    @ManyToMany
    @JoinTable(     name = "VERSION_NODES_ADDED",
                    joinColumns = { @JoinColumn(name = "VERSION_ID") },
    		        inverseJoinColumns = { @JoinColumn(name = "NODE_ID") })
//    @CollectionId(  columns   = @Column(name = "id"),
//                    type      = @Type(type="big_integer"),
//                    generator = "native" )
    //@SequenceGenerator(name = "seq_version_nodes_added", sequenceName = "seq_version_nodes_added", allocationSize = 1)
    private Collection<KiWiNode> addedNodes;


    /**
     * The nodes that have been removed in this version
     */
    @ManyToMany
    @JoinTable(     name = "VERSION_NODES_REMOVED",
                    joinColumns = { @JoinColumn(name = "VERSION_ID") },
    		        inverseJoinColumns = { @JoinColumn(name = "NODE_ID") })
//    @CollectionId(  columns   = @Column(name = "id"),
//                    type      = @Type(type="big_integer"),
//                    generator = "native" )
    //@SequenceGenerator(name = "seq_version_nodes_removed", sequenceName = "seq_version_nodes_removed", allocationSize = 1)
    private Collection<KiWiNode> removedNodes;


    /**
     * The triples that have been added in this version
     */

    @ManyToMany
    @JoinTable(     name = "VERSION_TRIPLES_ADDED",
                    joinColumns = { @JoinColumn(name = "VERSION_ID") },
    		        inverseJoinColumns = { @JoinColumn(name = "TRIPLE_ID") })
//    @CollectionId(  columns   = @Column(name = "id"),
//                    type      = @Type(type="big_integer"),
//                    generator = "native" )
    //@SequenceGenerator(name = "seq_version_triples_added", sequenceName = "seq_version_triples_added", allocationSize = 1)
    private Collection<KiWiTriple> addedTriples;


    /**
     * The triples that have been removed in this version
     */

    @ManyToMany
    @JoinTable(     name = "VERSION_TRIPLES_REMOVED",
                    joinColumns = { @JoinColumn(name = "VERSION_ID") },
                    inverseJoinColumns = { @JoinColumn(name = "TRIPLE_ID") })
//    @CollectionId(  columns   = @Column(name = "id"),
//                    type      = @Type(type="big_integer"),
//                    generator = "native" )
    //@SequenceGenerator(name = "seq_version_triples_removed", sequenceName = "seq_version_triples_removed", allocationSize = 1)
    private Collection<KiWiTriple> removedTriples;

    /**
     * The triples that have been added in this version
     */

    @ManyToMany
    @JoinTable(     name = "VERSION_NAMESPACES_ADDED",
                    joinColumns = { @JoinColumn(name = "VERSION_ID") },
    		        inverseJoinColumns = { @JoinColumn(name = "NAMESPACE_ID") })
//    @CollectionId(  columns   = @Column(name = "id"),
//                    type      = @Type(type="big_integer"),
//                    generator = "native" )
    //@SequenceGenerator(name = "seq_version_namespaces_added", sequenceName = "seq_version_namespaces_added", allocationSize = 1)
    private Collection<KiWiNamespace> addedNamespaces;


    /**
     * The triples that have been removed in this version
     */

    @ManyToMany
    @JoinTable(     name = "VERSION_NAMESPACES_REMOVED",
            joinColumns = { @JoinColumn(name = "VERSION_ID") },
            inverseJoinColumns = { @JoinColumn(name = "NAMESPACE_ID") })
//    @CollectionId(  columns   = @Column(name = "id"),
//            type      = @Type(type="big_integer"),
//            generator = "native" )
    //@SequenceGenerator(name = "seq_version_namespaces_removed", sequenceName = "seq_version_namespaces_removed", allocationSize = 1)
    private Collection<KiWiNamespace> removedNamespaces;


    /**
     * The user who has created the version.
     */
    @ManyToOne
    private KiWiUser creator;


    /**
     * The creation time of the version
     */
    @Temporal(TemporalType.TIMESTAMP)
    private Date created;


    /**
     * Optimistic Locking ...
     */
    @javax.persistence.Version
    private Long version;


    public Version() {
        created = new Date();
    }


    // getters and setters

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Collection<KiWiNode> getAddedNodes() {
        return addedNodes;
    }

    public void setAddedNodes(Set<KiWiNode> addedNodes) {
        this.addedNodes = addedNodes;
    }

    public Collection<KiWiNode> getRemovedNodes() {
        return removedNodes;
    }

    public void setRemovedNodes(Set<KiWiNode> removedNodes) {
        this.removedNodes = removedNodes;
    }

    public Collection<KiWiTriple> getAddedTriples() {
        return addedTriples;
    }

    public void setAddedTriples(Set<KiWiTriple> addedTriples) {
        this.addedTriples = addedTriples;
    }

    public Collection<KiWiTriple> getRemovedTriples() {
        return removedTriples;
    }

    public void setRemovedTriples(Set<KiWiTriple> removedTriples) {
        this.removedTriples = removedTriples;
    }

    public Collection<KiWiNamespace> getAddedNamespaces() {
        return addedNamespaces;
    }

    public void setAddedNamespaces(Set<KiWiNamespace> addedNamespaces) {
        this.addedNamespaces = addedNamespaces;
    }

    public Collection<KiWiNamespace> getRemovedNamespaces() {
        return removedNamespaces;
    }

    public void setRemovedNamespaces(Set<KiWiNamespace> removedNamespaces) {
        this.removedNamespaces = removedNamespaces;
    }

    public Date getCreated() {
        return created;
    }

    public void setCreated(Date created) {
        this.created = created;
    }

    public Long getVersion() {
        return version;
    }

    public void setVersion(Long version) {
        this.version = version;
    }

    public KiWiUser getCreator() {
        return creator;
    }

    public void setCreator(KiWiUser author) {
        this.creator = author;
    }
}
